//
//  YUVRotate.h
//  Neye 3C
//
//  Created by 罗英 on 2023/12/7.
//  Copyright © 2023 LT. All rights reserved.
//

#ifndef YUVRotate_h
#define YUVRotate_h

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>

// Supported rotation.
typedef enum RotationMode {
  kRotate0 = 0,  // No rotation.
  kRotate90 = 90,  // Rotate 90 degrees clockwise.
  kRotate180 = 180,  // Rotate 180 degrees.
  kRotate270 = 270,  // Rotate 270 degrees clockwise.

  // Deprecated.
  kRotateNone = 0,
  kRotateClockwise = 90,
  kRotateCounterClockwise = 270,
} RotationModeEnum;

typedef enum FilterMode {
  kFilterNone = 0,  // Point sample; Fastest.
  kFilterLinear = 1,  // Filter horizontally only.
  kFilterBilinear = 2,  // Faster than box, but lower quality scaling down.
  kFilterBox = 3  // Highest quality.
} FilterModeEnum;

#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
#define MIN1(x) ((x) < 1 ? 1 : (x))

#define uint8_t unsigned char
#define uint8 uint8_t
#define uint16_t unsigned short
#define uint16 uint16_t

#ifdef __cplusplus
#define align_buffer_64(var, size)                                             \
  uint8* var##_mem = reinterpret_cast<uint8*>(malloc((size) + 63));            \
  uint8* var = reinterpret_cast<uint8*>                                        \
      ((reinterpret_cast<intptr_t>(var##_mem) + 63) & ~63)
#else
#define align_buffer_64(var, size)                                             \
  uint8* var##_mem = (uint8*)(malloc((size) + 63));               /* NOLINT */ \
  uint8* var = (uint8*)(((intptr_t)(var##_mem) + 63) & ~63)       /* NOLINT */
#endif

#define free_aligned_buffer_64(var) \
  free(var##_mem);  \
  var = 0



int NV12ToI420Rotate(const uint8_t* src_y, int src_stride_y,
                     const uint8_t* src_uv, int src_stride_uv,
                     uint8_t* dst_y, int dst_stride_y,
                     uint8_t* dst_u, int dst_stride_u,
                     uint8_t* dst_v, int dst_stride_v,
                     int src_width, int src_height, enum RotationMode mode);

int NV12ToI420(const uint8_t* src_y, int src_stride_y,
               const uint8_t* src_uv, int src_stride_uv,
               uint8_t* dst_y, int dst_stride_y,
               uint8_t* dst_u, int dst_stride_u,
               uint8_t* dst_v, int dst_stride_v,
               int width, int height);

int I420ToNV12(const uint8_t* src_y, int src_stride_y,
               const uint8_t* src_u, int src_stride_u,
               const uint8_t* src_v, int src_stride_v,
               uint8_t* dst_y, int dst_stride_y,
               uint8_t* dst_uv, int dst_stride_uv,
               int width, int height);

void RotatePlane90(const uint8_t* src, int src_stride,
                   uint8_t* dst, int dst_stride,
                   int width, int height);


void RotateUV90(const uint8_t* src, int src_stride,
                uint8_t* dst_a, int dst_stride_a,
                uint8_t* dst_b, int dst_stride_b,
                int width, int height);

void RotatePlane270(const uint8_t* src, int src_stride,
                    uint8_t* dst, int dst_stride,
                    int width, int height);


void RotateUV270(const uint8_t* src, int src_stride,
                 uint8_t* dst_a, int dst_stride_a,
                 uint8_t* dst_b, int dst_stride_b,
                 int width, int height);

int X420ToI420(const uint8_t* src_y,
                      int src_stride_y0, int src_stride_y1,
                      const uint8_t* src_uv, int src_stride_uv,
                      uint8_t* dst_y, int dst_stride_y,
                      uint8_t* dst_u, int dst_stride_u,
                      uint8_t* dst_v, int dst_stride_v,
                      int width, int height);

void TransposePlane(const uint8_t* src, int src_stride,
                    uint8_t* dst, int dst_stride,
                    int width, int height);


void TransposeUV(const uint8_t* src, int src_stride,
                 uint8_t* dst_a, int dst_stride_a,
                 uint8_t* dst_b, int dst_stride_b,
                 int width, int height);


void SplitUVRow_C(const uint8_t* src_uv, uint8_t* dst_u, uint8_t* dst_v, int pix);


void CopyPlane(const uint8_t* src_y, int src_stride_y,
               uint8_t* dst_y, int dst_stride_y,
               int width, int height);

void CopyPlane2(const uint8_t* src, int src_stride_0, int src_stride_1,
                       uint8_t* dst, int dst_stride,
                       int width, int height);

void TransposeWx8_C(const uint8_t* src, int src_stride,
                           uint8_t* dst, int dst_stride,
                           int width) ;

void TransposeWxH_C(const uint8_t* src, int src_stride,
                           uint8_t* dst, int dst_stride,
                           int width, int height);

void TransposeUVWx8_C(const uint8_t* src, int src_stride,
                             uint8_t* dst_a, int dst_stride_a,
                             uint8_t* dst_b, int dst_stride_b,
                             int width);

void TransposeUVWxH_C(const uint8_t* src, int src_stride,
                             uint8_t* dst_a, int dst_stride_a,
                             uint8_t* dst_b, int dst_stride_b,
                             int width, int height);

void CopyRow_C(const uint8_t* src, uint8_t* dst, int count);


void MergeUVRow_C(const uint8_t* src_u, const uint8_t* src_v, uint8_t* dst_uv,
                  int width);


int I420Scale(const uint8_t* src_y, int src_stride_y,
              const uint8_t* src_u, int src_stride_u,
              const uint8_t* src_v, int src_stride_v,
              int src_width, int src_height,
              uint8_t* dst_y, int dst_stride_y,
              uint8_t* dst_u, int dst_stride_u,
              uint8_t* dst_v, int dst_stride_v,
              int dst_width, int dst_height,
              enum FilterMode filtering);


void ScalePlane(const uint8_t* src, int src_stride,
                int src_width, int src_height,
                uint8_t* dst, int dst_stride,
                int dst_width, int dst_height,
                enum FilterMode filtering);

enum FilterMode ScaleFilterReduce(int src_width, int src_height,
                                  int dst_width, int dst_height,
                                  enum FilterMode filtering);
#define FixedDiv FixedDiv_C

#define FixedDiv1 FixedDiv1_C

int FixedDiv_C(int num, int div);
int FixedDiv1_C(int num, int div);

void ScalePlaneVertical(int src_height,
                        int dst_width, int dst_height,
                        int src_stride, int dst_stride,
                        const uint8_t* src_argb, uint8_t* dst_argb,
                        int x, int y, int dy,
                        int bpp, enum FilterMode filtering);

void ScalePlaneDown34(int src_width, int src_height,
                             int dst_width, int dst_height,
                             int src_stride, int dst_stride,
                             const uint8_t* src_ptr, uint8_t* dst_ptr,
                      enum FilterMode filtering);

void ScaleRowDown34_C(const uint8_t* src_ptr, ptrdiff_t src_stride,
                      uint8_t* dst, int dst_width);

void ScaleRowDown34_0_Box_C(const uint8_t* src_ptr, ptrdiff_t src_stride,
                            uint8_t* d, int dst_width);

void ScaleRowDown34_1_Box_C(const uint8_t* src_ptr, ptrdiff_t src_stride,
                            uint8_t* d, int dst_width);

void ScalePlaneDown2(int src_width, int src_height,
                            int dst_width, int dst_height,
                            int src_stride, int dst_stride,
                            const uint8_t* src_ptr, uint8_t* dst_ptr,
                     enum FilterMode filtering);

void ScalePlaneDown38(int src_width, int src_height,
                             int dst_width, int dst_height,
                             int src_stride, int dst_stride,
                             const uint8_t* src_ptr, uint8_t* dst_ptr,
                      enum FilterMode filtering);

void ScalePlaneDown4(int src_width, int src_height,
                            int dst_width, int dst_height,
                            int src_stride, int dst_stride,
                            const uint8_t* src_ptr, uint8_t* dst_ptr,
                     enum FilterMode filtering);

void ScalePlaneBox(int src_width, int src_height,
                          int dst_width, int dst_height,
                          int src_stride, int dst_stride,
                   const uint8_t* src_ptr, uint8_t* dst_ptr);

void ScalePlaneBilinearUp(int src_width, int src_height,
                          int dst_width, int dst_height,
                          int src_stride, int dst_stride,
                          const uint8_t* src_ptr, uint8_t* dst_ptr,
                          enum FilterMode filtering);

void ScalePlaneBilinearDown(int src_width, int src_height,
                            int dst_width, int dst_height,
                            int src_stride, int dst_stride,
                            const uint8_t* src_ptr, uint8_t* dst_ptr,
                            enum FilterMode filtering);

void ScalePlaneSimple(int src_width, int src_height,
                             int dst_width, int dst_height,
                             int src_stride, int dst_stride,
                      const uint8_t* src_ptr, uint8_t* dst_ptr);

void InterpolateRow_C(uint8_t* dst_ptr, const uint8_t* src_ptr,
                      ptrdiff_t src_stride_ptr,
                      int width, int source_y_fraction);

void ScaleRowDown2_C(const uint8_t* src_ptr, ptrdiff_t src_stride,
                     uint8_t* dst, int dst_width);

void ScaleRowDown2Linear_C(const uint8_t* src_ptr, ptrdiff_t src_stride,
                           uint8_t* dst, int dst_width);

void ScaleRowDown2Box_C(const uint8_t* src_ptr, ptrdiff_t src_stride,
                        uint8_t* dst, int dst_width);

void ScaleRowDown38_C(const uint8_t* src_ptr, ptrdiff_t src_stride,
                      uint8_t* dst, int dst_width);

void ScaleRowDown38_3_Box_C(const uint8_t* src_ptr,
                            ptrdiff_t src_stride,
                            uint8_t* dst_ptr, int dst_width);

void ScaleRowDown38_2_Box_C(const uint8_t* src_ptr, ptrdiff_t src_stride,
                            uint8_t* dst_ptr, int dst_width);

void ScaleRowDown4Box_C(const uint8_t* src_ptr, ptrdiff_t src_stride,
                        uint8_t* dst, int dst_width);

void ScaleRowDown4_C(const uint8* src_ptr, ptrdiff_t src_stride,
                     uint8* dst, int dst_width);

void ScaleSlope(int src_width, int src_height,
                int dst_width, int dst_height,
                enum FilterMode filtering,
                int* x, int* y, int* dx, int* dy);


void ScaleAddCols2_C(int dst_width, int boxheight, int x, int dx,
                     const uint16* src_ptr, uint8* dst_ptr) ;

void ScaleAddCols1_C(int dst_width, int boxheight, int x, int dx,
                     const uint16* src_ptr, uint8* dst_ptr);

void ScaleAddCols0_C(int dst_width, int boxheight, int x, int y,
                     const uint16* src_ptr, uint8* dst_ptr);

void ScaleAddRow_C(const uint8* src_ptr, uint16* dst_ptr, int src_width);

void ScaleFilterCols_C(uint8* dst_ptr, const uint8* src_ptr,
                       int dst_width, int x, int dx);

void ScaleCols_C(uint8* dst_ptr, const uint8* src_ptr,
                 int dst_width, int x, int dx);

void ScaleFilterCols64_C(uint8* dst_ptr, const uint8* src_ptr,
                         int dst_width, int x, int dx);

void ScaleColsUp2_C(uint8* dst_ptr, const uint8* src_ptr,
                    int dst_width, int, int);

int I420Rotate(const uint8* src_y, int src_stride_y,
               const uint8* src_u, int src_stride_u,
               const uint8* src_v, int src_stride_v,
               uint8* dst_y, int dst_stride_y,
               uint8* dst_u, int dst_stride_u,
               uint8* dst_v, int dst_stride_v,
               int src_width, int src_height, enum RotationMode mode);

void RotatePlane180(const uint8* src, int src_stride,
                    uint8* dst, int dst_stride,
                    int width, int height);

void MirrorRow_C(const uint8* src, uint8* dst, int width);

int I420ToNV21(const uint8* src_y, int src_stride_y,
               const uint8* src_u, int src_stride_u,
               const uint8* src_v, int src_stride_v,
               uint8* dst_y, int dst_stride_y,
               uint8* dst_vu, int dst_stride_vu,
               int width, int height);
#endif
